﻿using System;
using System.Data;
using System.Data.Common;

namespace Petaframe.DataAccess
{
    /// <summary>
    /// <see cref="DataTable"/> ile çalışmak için gerekli metodları sağlar.
    /// </summary>
    public class DetachedQuery : IDetachedQuery 
    {

         DataService _dataService;   
         readonly string _connectionString;

        public DetachedQuery(IDataService dataService,string connectionString)
        {
            _dataService =(DataService) dataService;            
            _connectionString = connectionString;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_dataService != null)
                {
                    _dataService.Dispose();
                    _dataService = null;
                }
            }

        }
        ~DetachedQuery()
        {
            Dispose(false);
        }

        /// <summary>
        /// Select işlemleri için kullanılır.
        /// </summary>
        /// <param name="commandText">Select cümlesi.</param>
        /// <param name="commandType">Komut tipi.</param>
        /// <returns>Select işleminin sonucu</returns>
        public DataTable FindAll(string commandText, CommandType commandType = CommandType.Text)
        {
            using (DbDataAdapter _dbAdapter = CreateDataAdapter(commandText))
            {
                _dataService.AddCommandParameters();
                DataTable table = new DataTable();
                try
                {
                    _dbAdapter.Fill(0, _dataService.MaxNumberOfResults, table);
                   
                }
                finally
                {
                    _dataService.ClearParameters();
                }
                return table;
            }
        }

        /// <summary>
        /// Parametre olarak verilen datatable ile insert,update veya delete işlemlerini yapar.
        /// </summary>
        /// <param name="table">İşlem yapılacak olan datatable.</param>
        /// <returns>Etkilenen satır sayısı.</returns>
        public int PersistTable(DataTable table)
        {
            if (string.IsNullOrWhiteSpace(table.TableName))
                throw new ArgumentNullException("Tablo ismi verilmediği için işlem yapılamaz. DataTable.TableName property değeri verilmelidir.");            

            
            using (DbDataAdapter _dbAdapter = CreateDataAdapter(string.Format("select * from {0}", table.TableName)))
            {
                DbCommandBuilder commandBuilder = _dataService._dbProviderFactory.CreateCommandBuilder();
                commandBuilder.DataAdapter = _dbAdapter;

                _dbAdapter.InsertCommand = commandBuilder.GetInsertCommand();
                _dbAdapter.UpdateCommand = commandBuilder.GetUpdateCommand();
                _dbAdapter.DeleteCommand = commandBuilder.GetDeleteCommand();
                if (_dataService._dbTransaction != null)
                {
                    //transaction başlatıldıysa
                    _dbAdapter.InsertCommand.Transaction = _dataService._dbTransaction;
                    _dbAdapter.UpdateCommand.Transaction = _dataService._dbTransaction;
                    _dbAdapter.DeleteCommand.Transaction = _dataService._dbTransaction;
                }
                return _dbAdapter.Update(table);
            }                       
        }    

        /// <summary>
        /// Sorgu sonucunu sayfalayarak getirmek için kullanılır.
        /// </summary>
        /// <param name="commandText">Select sorgusu.</param>
        /// <param name="currentPage">Sayfa numarası</param>
        /// <param name="pageSize">Her sayfada gösterilecek satır sayısı.</param>
        /// <returns>Sorgu sonucu.</returns>
        public DataTable Page(string commandText, int currentPage = 1, int pageSize = 20)
        {          
            using (DbDataAdapter _dbAdapter = CreateDataAdapter(commandText))
            {
                DataTable table = new DataTable();
                _dataService.AddCommandParameters();
                try
                {
                    _dbAdapter.Fill((currentPage - 1) * pageSize, pageSize, table);
                    
                }
                finally
                {
                    _dataService.ClearParameters();
                }
                return table;
            }           
        }

        private DbDataAdapter CreateDataAdapter(string selectCommandText)
        {
            if (_dataService._dbConnection == null)
                _dataService._dbConnection =_dataService.CreateConnection(_connectionString);

            if (_dataService._dbCommand == null)
                _dataService._dbCommand = _dataService.CreateCommand(_dataService._dbConnection);
            else
            {               
                _dataService._dbCommand.Parameters.Clear();
            }
           
            _dataService._dbCommand.CommandText = selectCommandText;

            var adapter =_dataService._dbProviderFactory.CreateDataAdapter();
            adapter.SelectCommand = _dataService._dbCommand;
            return adapter;
        }
    }
}
